// #define DONOT_USE_RSEQ
#define _GNU_SOURCE
#include <assert.h>
#include <stdlib.h>
#include <libapfsds.h>
#include <ddblk_plat.h>
#include <dbg.h>
#include <dbg/ptest.h>
#include <pthreadalt.h>

#include <add.h>
#include <htable.h>
#include <nop.h>
#include <queue.h>
#include <stack.h>
#include <rbtree.h>
#include <tlsf.h>

#ifndef HDEF_LITTLECORE_OFFST
	#warning "undefined LITTLECORE_OFFST"
	#define HDEF_LITTLECORE_OFFST	0
#endif


#define TEST_NR		(100000)
#define TEST_LOCKS	(1)

/* 执行线程数 */
/* 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24 */
/* 1, 2, 4, 8, 12, 16, 20, 24, 36, 48, 60, 72 */
#ifndef TEST_THREADNR
	#define TEST_THREADNR			(HDEF_NATIVE_CPU_NR)
	#if (HDEF_NATIVE_CPU_NR == 8)
		#define WARMUP_THREAD_NR	16
		static const word_t test_nrs_arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
	#elif (HDEF_NATIVE_CPU_NR == 16)
		#define WARMUP_THREAD_NR	16
		static const word_t test_nrs_arr[] = {1, 2, 4, 6, 8, 11, 13, 16};
	#elif (HDEF_NATIVE_CPU_NR == 24)
		#define WARMUP_THREAD_NR	24
		static const word_t test_nrs_arr[] = {1, 2, 4, 8, 12, 16, 20, 24};
	#endif
#endif


static apfsds_t *apfsds[TEST_LOCKS];
static addcount_t addcnt;
static addcount_t addcnts[TEST_LOCKS];
static queue_t queue;
static sstack_t stack;

static apfsds_t *apfsds_stack;
static apfsds_t *apfsds_queue;
static apfsds_t *apfsds_htable;
static apfsds_t *apfsds_rbtree;
static apfsds_t *apfsds_tlsf;

#define HTABLE_SIZE (HDEF_NATIVE_CPU_NR*HDEF_NATIVE_CPU_NR)
static htable_t *htable;

static struct rb_root rbroot = {0};

static TLS_INITIAL tid_t mytid;
#define MAX_ALLOCATION_SIZE (4096)
#define TLSF_POOL_SIZE (MAX_ALLOCATION_SIZE * 64)
static tlsf_t tlsf;

static TLS_INITIAL bool_t qpush;
static TLS_INITIAL queuenode_t *qnode;
static TLS_INITIAL bool_t spush;
static TLS_INITIAL stacknode_t *snode;
static TLS_INITIAL bool_t hpush;
static TLS_INITIAL hnode_t *hnode;
static TLS_INITIAL struct mynode *rnode;
static TLS_INITIAL bool_t rpush;
static TLS_INITIAL void *mem;
static TLS_INITIAL bool_t bmalloc;
static void bench_sync_once(word_t nr){


	word_t key = mytid + HDEF_NATIVE_CPU_NR;
	word_t size;

	/* duff's device随机化 */
	{
		WRAP_ARGS(ar, &addcnt);
		apfsds_sync(apfsds[0], count_add_cb, ar);
	}
	
	/* 队列 */
	{
		qpush = !qpush;
		if (qpush){
			WRAP_ARGS(ar, &queue, qnode);
			qnode = NULL;
			apfsds_sync(apfsds_queue, queue_push_tail_cb, ar);

		}else{
			WRAP_ARGS(ar, &queue);
			qnode = (void *)apfsds_sync(apfsds_queue, queue_pop_head_cb, ar);
			qnode->val = (void *)nr;
			if(!qnode) fatal("!!\n");
		}
	}
	/* 栈 */
	{
		spush = !spush;
		if (spush){
			WRAP_ARGS(ar, &stack, snode);
			snode = NULL;
			apfsds_sync(apfsds_stack, stack_push_cb, ar);

		}else{
			WRAP_ARGS(ar, &stack);
			snode = (void *)apfsds_sync(apfsds_stack, stack_pop_cb, ar);
			snode->val = (void *)nr;
			if(!snode) fatal("!!\n");
		}
	}
	/* hash */
	{
		hpush = !hpush;
		if (hpush){
			WRAP_ARGS(ar, htable, hnode);
			hnode->key = key;
			hnode = NULL;
			apfsds_sync(apfsds_htable, htable_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, htable, key);
			hnode = (void *)apfsds_sync(apfsds_htable, htable_remove_cb, ar);
			if (!hnode)
				fatal("!!\n");
		}
	}
	/* rbtree */
	{
		rpush = !rpush;
		if (rpush){
			WRAP_ARGS(ar, &rbroot, rnode);
			rnode->key = key;
			rnode = NULL;
			apfsds_sync(apfsds_rbtree, rbtree_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, &rbroot, key);
			rnode = (void *)apfsds_sync(apfsds_rbtree, rbtree_remove_cb, ar);
			if (!rnode)
				fatal("!!\n");
		}
	}
	/* tlsf */
	{
		bmalloc = !bmalloc;
		if (bmalloc){
			size = hash(rdcnt_relax()) % MAX_ALLOCATION_SIZE;
			size |= 1; /* 确保size 至少为1 */
			WRAP_ARGS(ar, tlsf, size);
			mem = (void *)apfsds_sync(apfsds_tlsf, tlsf_malloc_cb, ar);
			if (!mem) fatal("malloc error, size %lu\n", size);
		}else{
			WRAP_ARGS(ar, tlsf, mem);
			apfsds_sync(apfsds_tlsf, tlsf_free_cb, ar);
		}
	}
}

static void bench_async_once(word_t nr){

	word_t key = mytid + HDEF_NATIVE_CPU_NR;
	apfsds_future_t *futs[7];
	word_t fut_idx = 0;
	{
		WRAP_ARGS(ar, &addcnt);
		futs[fut_idx++] = apfsds_fetch(apfsds[0], count_add_cb, ar);
	}
	
	/* 队列 */
	{
		qpush = !qpush;
		if (qpush){
			WRAP_ARGS(ar, &queue, qnode);
			qnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_queue, queue_push_tail_cb, ar);

		}else{
			WRAP_ARGS(ar, &queue);
			futs[fut_idx++] = apfsds_fetch(apfsds_queue, queue_pop_head_cb, ar);
		}
	}
	/* 栈 */
	{
		spush = !spush;
		if (spush){
			WRAP_ARGS(ar, &stack, snode);
			snode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_stack, stack_push_cb, ar);

		}else{
			WRAP_ARGS(ar, &stack);
			futs[fut_idx++] = apfsds_fetch(apfsds_stack, stack_pop_cb, ar);
		}
	}
	/* hash */
	{
		hpush = !hpush;
		if (hpush){
			WRAP_ARGS(ar, htable, hnode);
			hnode->key = key;
			hnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_htable, htable_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, htable, key);
			futs[fut_idx++] = apfsds_fetch(apfsds_htable, htable_remove_cb, ar);
		}
	}
	/* rbtree */
	{
		rpush = !rpush;
		if (rpush){
			WRAP_ARGS(ar, &rbroot, rnode);
			rnode->key = key;
			rnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_rbtree, rbtree_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, &rbroot, key);
			futs[fut_idx++] = apfsds_fetch(apfsds_rbtree, rbtree_remove_cb, ar);
		}
	}
	/* tlsf */
	{
		bmalloc = !bmalloc;
		if (bmalloc){
			word_t size = hash(rdcnt_relax()) % MAX_ALLOCATION_SIZE;
			size |= 1; /* 确保size 至少为1 */
			WRAP_ARGS(ar, tlsf, size);
			futs[fut_idx++] = apfsds_fetch(apfsds_tlsf, tlsf_malloc_cb, ar);
		}else{
			WRAP_ARGS(ar, tlsf, mem);
			futs[fut_idx++] = apfsds_fetch(apfsds_tlsf, tlsf_free_cb, ar);
		}
	}

	/* 依次等待所有结果 */
	word_t fut_ret[6];

	/* duff's device */
	/* 如何把duff's device封装成宏呢? */
	word_t seed = hash(nr + key) % 8;
	word_t sidx = 0;
	switch(seed){
	RETRY:
		case 0:
			if (sidx >= 6) break;
			fut_ret[0] = apfsds_wait(apfsds[0], futs[0]);
			sidx++;
		case 1:
			if (sidx >= 6) break;
			fut_ret[1] = apfsds_wait(apfsds_queue, futs[1]);
			sidx++;
		case 2:
			if (sidx >= 6) break;
			fut_ret[2] = apfsds_wait(apfsds_stack, futs[2]);
			sidx++;
		case 3:
			if (sidx >= 6) break;
			fut_ret[3] = apfsds_wait(apfsds_htable, futs[3]);
			sidx++;
		case 4:
			if (sidx >= 6) break;
			fut_ret[4] = apfsds_wait(apfsds_rbtree, futs[4]);
			sidx++;
		case 5:
			if (sidx >= 6) break;
			fut_ret[5] = apfsds_wait(apfsds_tlsf, futs[5]);
			sidx++;
		default:
			goto RETRY;
	}

	// apfsds_wait_all(fut_ret, (apfsds[0], futs[0]), (apfsds_queue, futs[1]), (apfsds_stack, futs[2]),\
	// 			(apfsds_htable, futs[3]), (apfsds_rbtree, futs[4]), (apfsds_tlsf, futs[5]));
	fut_idx = 0;
	{
		// apfsds_wait(apfsds[0], futs[fut_idx]);
	}
	fut_idx++;
	/* 队列 */
	{
		if (qpush){
			// apfsds_wait(apfsds_queue, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &queue);
			// qnode = (void *)apfsds_wait(apfsds_queue, futs[fut_idx]);
			qnode = (void *)fut_ret[fut_idx];
			qnode->val = (void *)nr;
			if(!qnode) fatal("!!\n");
		}
	}
	fut_idx++;
	/* 栈 */
	{
		if (spush){
			// apfsds_wait(apfsds_stack, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &stack);
			// snode = (void *)apfsds_wait(apfsds_stack, futs[fut_idx]);
			snode = (void *)fut_ret[fut_idx];
			snode->val = (void *)nr;
			if(!snode) fatal("!!\n");
		}
	}
	fut_idx++;
	/* hash */
	{
		if (hpush){
			// apfsds_wait(apfsds_htable, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, htable, key);
			// hnode = (void *)apfsds_wait(apfsds_htable, futs[fut_idx]);
			hnode = (void *)fut_ret[fut_idx];
			if (!hnode)
				fatal("!!\n");
		}
	}
	fut_idx++;
	/* rbtree */
	{
		if (rpush){
			// apfsds_wait(apfsds_rbtree, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &rbroot, key);
			// rnode = (void *)apfsds_wait(apfsds_rbtree, futs[fut_idx]);
			rnode = (void *)fut_ret[fut_idx];
			if (!rnode)
				fatal("!!\n");
		}
	}
	fut_idx++;
	/* tlsf */
	{
		if (bmalloc){
			// mem = (void *)apfsds_wait(apfsds_tlsf, futs[fut_idx]);
			mem = (void *)fut_ret[fut_idx];
			if (!mem) fatal("malloc error");
		}else{
			// apfsds_wait(apfsds_tlsf, futs[fut_idx]);
		}
	}
	fut_idx++;
}
/* 逆序 */
static void bench_async_once_rev(word_t nr){

	word_t key = mytid + HDEF_NATIVE_CPU_NR;
	apfsds_future_t *futs[7];
	word_t fut_idx = 0;
	{
		WRAP_ARGS(ar, &addcnt);
		futs[fut_idx++] = apfsds_fetch(apfsds[0], count_add_cb, ar);
	}
	
	/* 队列 */
	{
		qpush = !qpush;
		if (qpush){
			WRAP_ARGS(ar, &queue, qnode);
			qnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_queue, queue_push_tail_cb, ar);

		}else{
			WRAP_ARGS(ar, &queue);
			futs[fut_idx++] = apfsds_fetch(apfsds_queue, queue_pop_head_cb, ar);
		}
	}
	/* 栈 */
	{
		spush = !spush;
		if (spush){
			WRAP_ARGS(ar, &stack, snode);
			snode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_stack, stack_push_cb, ar);

		}else{
			WRAP_ARGS(ar, &stack);
			futs[fut_idx++] = apfsds_fetch(apfsds_stack, stack_pop_cb, ar);
		}
	}
	/* hash */
	{
		hpush = !hpush;
		if (hpush){
			WRAP_ARGS(ar, htable, hnode);
			hnode->key = key;
			hnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_htable, htable_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, htable, key);
			futs[fut_idx++] = apfsds_fetch(apfsds_htable, htable_remove_cb, ar);
		}
	}
	/* rbtree */
	{
		rpush = !rpush;
		if (rpush){
			WRAP_ARGS(ar, &rbroot, rnode);
			rnode->key = key;
			rnode = NULL;
			futs[fut_idx++] = apfsds_fetch(apfsds_rbtree, rbtree_insert_cb, ar);
		}else{
			WRAP_ARGS(ar, &rbroot, key);
			futs[fut_idx++] = apfsds_fetch(apfsds_rbtree, rbtree_remove_cb, ar);
		}
	}
	/* tlsf */
	{
		bmalloc = !bmalloc;
		if (bmalloc){
			word_t size = hash(rdcnt_relax()) % MAX_ALLOCATION_SIZE;
			size |= 1; /* 确保size 至少为1 */
			WRAP_ARGS(ar, tlsf, size);
			futs[fut_idx++] = apfsds_fetch(apfsds_tlsf, tlsf_malloc_cb, ar);
		}else{
			WRAP_ARGS(ar, tlsf, mem);
			futs[fut_idx++] = apfsds_fetch(apfsds_tlsf, tlsf_free_cb, ar);
		}
	}

	/* 依次等待所有结果 */
	word_t fut_ret[6];
	// apfsds_wait_all(fut_ret, (apfsds[0], futs[0]), (apfsds_queue, futs[1]), (apfsds_stack, futs[2]),\
	// 			(apfsds_htable, futs[3]), (apfsds_rbtree, futs[4]), (apfsds_tlsf, futs[5]));
	/* 改为乱序执行? */
	// word_t seed = hash(nr) % 8;
	// word_t sidx = 0;
	// switch(seed){
	// RETRY:
	// 	case 0:
	// 		if (sidx >= 6) break;
	// 		fut_ret[5] = apfsds_wait(apfsds[0], futs[0]);
	// 		sidx++;
	// 	case 1:
	// 		if (sidx >= 6) break;
	// 		fut_ret[4] = apfsds_wait(apfsds_queue, futs[1]);
	// 		sidx++;
	// 	case 2:
	// 		if (sidx >= 6) break;
	// 		fut_ret[3] = apfsds_wait(apfsds_stack, futs[2]);
	// 		sidx++;
	// 	case 3:
	// 		if (sidx >= 6) break;
	// 		fut_ret[2] = apfsds_wait(apfsds_htable, futs[3]);
	// 		sidx++;
	// 	case 4:
	// 		if (sidx >= 6) break;
	// 		fut_ret[1] = apfsds_wait(apfsds_rbtree, futs[4]);
	// 		sidx++;
	// 	case 5:
	// 		if (sidx >= 6) break;
	// 		fut_ret[0] = apfsds_wait(apfsds_tlsf, futs[5]);
	// 		sidx++;
	// 	default:
	// 		goto RETRY;
	// }

	apfsds_wait_all(fut_ret, (apfsds_tlsf, futs[5]), (apfsds_rbtree, futs[4]), (apfsds_htable, futs[3]),\
				(apfsds_stack, futs[2]), (apfsds_queue, futs[1]),  (apfsds[0], futs[0]));
			
	fut_idx = 5;
	{
		// apfsds_wait(apfsds[0], futs[fut_idx]);
	}
	fut_idx--;
	/* 队列 */
	{
		if (qpush){
			// apfsds_wait(apfsds_queue, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &queue);
			// qnode = (void *)apfsds_wait(apfsds_queue, futs[fut_idx]);
			qnode = (void *)fut_ret[fut_idx];
			qnode->val = (void *)nr;
			if(!qnode) fatal("!!\n");
		}
	}
	fut_idx--;
	/* 栈 */
	{
		if (spush){
			// apfsds_wait(apfsds_stack, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &stack);
			// snode = (void *)apfsds_wait(apfsds_stack, futs[fut_idx]);
			snode = (void *)fut_ret[fut_idx];
			snode->val = (void *)nr;
			if(!snode) fatal("!!\n");
		}
	}
	fut_idx--;
	/* hash */
	{
		if (hpush){
			// apfsds_wait(apfsds_htable, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, htable, key);
			// hnode = (void *)apfsds_wait(apfsds_htable, futs[fut_idx]);
			hnode = (void *)fut_ret[fut_idx];
			if (!hnode)
				fatal("!!\n");
		}
	}
	fut_idx--;
	/* rbtree */
	{
		if (rpush){
			// apfsds_wait(apfsds_rbtree, futs[fut_idx]);
		}else{
			WRAP_ARGS(ar, &rbroot, key);
			// rnode = (void *)apfsds_wait(apfsds_rbtree, futs[fut_idx]);
			rnode = (void *)fut_ret[fut_idx];
			if (!rnode)
				fatal("!!\n");
		}
	}
	fut_idx--;
	/* tlsf */
	{
		if (bmalloc){
			// mem = (void *)apfsds_wait(apfsds_tlsf, futs[fut_idx]);
			mem = (void *)fut_ret[fut_idx];
			if (!mem) fatal("malloc error");
		}else{
			// apfsds_wait(apfsds_tlsf, futs[fut_idx]);
		}
	}
	fut_idx--;
}

/* 先sync*/
static void *bench_sync(void *args){
	word_t test_nr = (word_t)args;
	qpush = 0;
	spush = 0;
	hpush = 0;
	rpush = 0;
	if (!qnode) qnode = (queuenode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(queuenode_t));
	if (!snode) snode = (stacknode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(stacknode_t) );
	if (!hnode) hnode = (hnode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(hnode_t));
	if (!rnode) rnode = (struct mynode *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(struct mynode));
	for (word_t idx = 0; idx < test_nr; idx++){
		bench_sync_once(idx);
		// printf("%lu\n", idx);
	}
	if (qnode) free(qnode);
	if (snode) free(snode);
	if (hnode) free(hnode);
	if (rnode) free(rnode);
	qnode = NULL;
	snode = NULL;
	hnode = NULL;
	rnode = NULL;
	return NULL;
}
/* 再async*/
static void *bench_async(void *args){
	word_t test_nr = (word_t)args;
	qpush = 0;
	spush = 0;
	hpush = 0;
	rpush = 0;
	if (!qnode) qnode = (queuenode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(queuenode_t));
	if (!snode) snode = (stacknode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(stacknode_t) );
	if (!hnode) hnode = (hnode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(hnode_t));
	if (!rnode) rnode = (struct mynode *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(struct mynode));
	for (word_t idx = 0; idx < test_nr; idx++){
		bench_async_once(idx);
		// printf("%lu\n", idx);
	}
	if (qnode) free(qnode);
	if (snode) free(snode);
	if (hnode) free(hnode);
	if (rnode) free(rnode);
	qnode = NULL;
	snode = NULL;
	hnode = NULL;
	rnode = NULL;
	return NULL;
}

/* 再async*/
static void *bench_async_rev(void *args){
	word_t test_nr = (word_t)args;
	qpush = 0;
	spush = 0;
	hpush = 0;
	rpush = 0;
	if (!qnode) qnode = (queuenode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(queuenode_t));
	if (!snode) snode = (stacknode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(stacknode_t) );
	if (!hnode) hnode = (hnode_t *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(hnode_t));
	if (!rnode) rnode = (struct mynode *)aligned_alloc(sizeof(HDEF_CACHE_LINE_BYTES), sizeof(struct mynode));
	for (word_t idx = 0; idx < test_nr; idx++){
		bench_async_once_rev(idx);
		// printf("%lu\n", idx);
	}
	if (qnode) free(qnode);
	if (snode) free(snode);
	if (hnode) free(hnode);
	if (rnode) free(rnode);
	qnode = NULL;
	snode = NULL;
	hnode = NULL;
	rnode = NULL;
	return NULL;
}
__PERF_PARALLEL_FUNC_BINDCORE_CUSTOM(bench_sync, mytid, TEST_NR, TEST_THREADNR, HDEF_LITTLECORE_OFFST, , test_nrs_arr, dbg_printf)
__PERF_PARALLEL_FUNC_BINDCORE_CUSTOM(bench_async, mytid, TEST_NR, TEST_THREADNR, HDEF_LITTLECORE_OFFST, , test_nrs_arr, dbg_printf)
__PERF_PARALLEL_FUNC_BINDCORE_CUSTOM(bench_async_rev, mytid, TEST_NR, TEST_THREADNR, HDEF_LITTLECORE_OFFST, , test_nrs_arr, dbg_printf)

int main(){
	for (word_t idx = 0; idx < TEST_LOCKS; idx++){
		// printf("%d\n", idx);
		apfsds[idx] = apfsds_create();
	}
	
	apfsds_stack = apfsds_create();
	apfsds_queue = apfsds_create();
	apfsds_htable = apfsds_create();
	apfsds_rbtree = apfsds_create();
	apfsds_tlsf = apfsds_create();

	count_init(&addcnt);
	for (word_t idx = 0; idx < TEST_LOCKS; idx++){
		count_init(&addcnts[idx]);
	}
	queue_init(&queue);
	stack_init(&stack);

	htable = htable_create(HTABLE_SIZE);
	for (word_t idx = 0; idx < HDEF_NATIVE_CPU_NR; idx++){
		hnode_t *node = (hnode_t *)malloc(sizeof(hnode_t));
		node->key = idx;
		htable_insert(htable, node);
	}

	my_rbinit(&rbroot);
	for (word_t idx = 0; idx < HDEF_NATIVE_CPU_NR; idx++){
		struct mynode *node = (struct mynode *)malloc(sizeof(struct mynode));
		node->key = idx;
		my_insert(&rbroot, node);
	}

	void *mem;
	int t = posix_memalign(&mem, 4096, TLSF_POOL_SIZE * HDEF_NATIVE_CPU_NR); // 8MB
	if (!mem || t != 0)
		fatal("tlsf memory alloc failed! %d\n", t);
	tlsf = tlsf_create_with_pool(mem, (size_t)(TLSF_POOL_SIZE * HDEF_NATIVE_CPU_NR));
	
	PERF_PARALLEL_RUN(bench_sync);
	PERF_PARALLEL_RUN(bench_async);
	// PERF_PARALLEL_RUN(bench_async_rev);
	for (word_t idx = 0; idx < TEST_LOCKS; idx++){
		apfsds_destroy(apfsds[idx]);
	}
	return 0;
}